/*
 * @Author: hongbin
 * @Date: 2022-11-27 10:40:24
 * @LastEditors: hongbin
 * @LastEditTime: 2022-12-03 21:01:19
 * @Description:控制其他用户在环境中的运行等形态同步
 */
import { IUserPartsConfig } from "../../components/CustomProfile/types";
import { acterWrapTemplate, renderControl, scene, acterWrap } from "../object";
import TWEEN from "@tweenjs/tween.js";
import { Quaternion, Vector3 } from "three";
import { AnimationPlayer } from "../helper/index";
import { otherUserWear } from "../PartsControl";
import { clearChildren } from "./clearChildren";
import { SocketManager } from "../../socket";

export interface INearbyUser {
    _id: string;
    name: string;
    distance: number;
}

export interface ISyncMove {
    _id: string;
    name: string;
    config: IUserPartsConfig["config1"];
    position: { x: number; y: number; z: number };
    quaternion: { _x: number; _y: number; _z: number; _w: number };
}

export class OtherUser {
    info: ISyncMove;
    model!: THREE.Group;
    acterAnimate = AnimationPlayer();
    moved = false;

    constructor(info: ISyncMove) {
        this.info = info;
        this.initActor();
    }

    /**
     * 检测配件更新
     */
    // checkPartsUpdate(curr: ISyncMove["config"], prev: ISyncMove["config"]) {}

    /**
     * 应用新的位置 设置每一帧的增量
     */
    updateUserInfo(info: ISyncMove, spaceTine: number) {
        if (
            info.position.x == this.info.position.x &&
            info.position.y == this.info.position.y &&
            info.position.z == this.info.position.z
        ) {
            return (this.moved = false);
        }
        this.moved = true;
        this.info = info;
        //同步位置
        // Object.assign(this.model.position, info.position);
        //同步朝向
        const { _x, _y, _z, _w } = info.quaternion;
        // this.model.quaternion.set(_x, _y, _z, _w);
        const targetQuaternion = new Quaternion(_x, _y, _z, _w);

        const p = new TWEEN.Tween(this.model.position)
            .to(info.position, spaceTine - 10)
            .easing(TWEEN.Easing.Linear.None)
            .start()
            .onComplete(() => {
                this.moved = false;
            });
        const q = new TWEEN.Tween(this.model.quaternion)
            .to(targetQuaternion, spaceTine)
            .easing(TWEEN.Easing.Linear.None)
            .start();
    }

    /**
     * 离去 清除
     */
    remove() {
        scene.remove(this.model);
        clearChildren(this.model as unknown as THREEMesh);
    }

    /**
     * 第一次 创建人物添加到scene中
     */
    initActor() {
        //添加人物模型
        const model = acterWrapTemplate.clone(true);
        this.model = model;
        Object.assign(model.position, this.info.position);
        scene.add(model);
        //添加人物配件 创建动画控制器 clone 的对象 没有 animations 使用一个即可
        otherUserWear(model, this.info.config, this.acterAnimate, acterWrapTemplate.children[0].animations);
    }

    update() {
        if (this.moved) {
            this.acterAnimate.start();
        } else this.acterAnimate.stop();
    }
}

/**
 * 维护所有其他在线人物的形态
 */
export class OtherUserList {
    /**
     * 自己的id
     */
    self: ISyncMove["_id"] = "";
    otherUsers: Record<string, OtherUser> = {};
    /**
     * 服务端收发信息的间隙
     */
    spaceTine = 1000;
    selfInfo: ISyncMove | undefined;
    _vector3 = new Vector3();
    _nearbyUsersChange: ((nearbyUsers: INearbyUser[]) => void) | undefined;

    constructor() {
        //清除离开的用户
        SocketManager.listen("leaveUserId", (leaveId) => {
            const leaveUser = this.otherUsers[leaveId];
            if (leaveUser) {
                leaveUser.remove();
                delete this.otherUsers[leaveId];
            }
        });
    }

    setSpaceTine(time: number) {
        this.spaceTine = time;
    }

    setSelf(id: string) {
        this.self = id;
    }

    updateAnimation() {
        TWEEN.update();
        Object.values(this.otherUsers).forEach((user) => user.update());
    }

    /**
     * 设置监听附近人变化的回调
     */
    nearbyUsersChange(callback: (nearbyUsers: INearbyUser[]) => void) {
        this._nearbyUsersChange = callback;
    }

    /**
     * 整理附近的人的信息
     */
    nearbyUsers() {
        //人物高度和对应距离的比例
        const proportion = 0.16;
        const nearbyUsers: INearbyUser[] = [];
        for (const [_id, user] of Object.entries(this.otherUsers)) {
            const {
                _id,
                name,
                position: { x, y, z },
            } = user.info;
            this._vector3.set(x, y, z);
            const distance = acterWrap.position.distanceTo(this._vector3) * proportion;
            if (distance < 20) {
                nearbyUsers.push({ _id, name, distance });
            }
        }
        //返回
        this._nearbyUsersChange && this._nearbyUsersChange(nearbyUsers);
    }

    /**
     * 新的同步数据
     */
    updateData(newData: Record<string, ISyncMove>) {
        for (const [_id, info] of Object.entries(newData)) {
            if (_id == this.self) {
                this.selfInfo = info;
                continue;
            }
            const saved = this.otherUsers[_id];
            //新增的
            if (!saved) {
                this.otherUsers[_id] = new OtherUser(info);
            }
            //维护以前的
            else {
                saved.updateUserInfo(info, this.spaceTine);
            }
        }
        this.nearbyUsers();
        //在服务端收发信息的间隙内 每个模型逐帧移动到目标位置
        renderControl.setRender(() => {
            window.render();
            this.updateAnimation();
        });
    }

    /**
     * 已废弃 使用离开任务监听 直接去掉 方案更佳
     * 检测人物是否有离开
     * TODO 应该逐个id检测 目前方案有漏洞
     */
    // removeLeavedUser(newData: Record<string, ISyncMove>) {
    //     const savedUsers = Object.keys(this.otherUsers);
    //     const currUsers = Object.keys(newData);
    //     //保存的数据不保存自己 所以数量+1
    //     if (savedUsers.length >= currUsers.length) {
    //         const leaveUserIds = savedUsers.filter((id) => !currUsers.includes(id));
    //         console.log("有用户离去:", leaveUserIds);
    //         leaveUserIds.forEach((id) => {
    //             console.log(this.otherUsers, id);

    //             this.otherUsers[id]?.remove();
    //             delete this.otherUsers[id];
    //         });
    //     }
    // }

    /**
     * socket计算到人数不足计算 - 清除其他用户
     */
    removeOtherUsers() {
        Object.values(this.otherUsers).forEach((user) => {
            user.remove();
        });
        this.otherUsers = {};
        this.nearbyUsers();
    }
}

export const otherUserList = new OtherUserList();
